package test.netty.core.chapter1.copy;

import lombok.extern.slf4j.Slf4j;
import test.netty.common.exceptions.NettyException;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * <p>标题: CopyFileDemo</p>
 * <p>功能描述: </p>
 *
 * <p>创建时间: 2021-04-02,23:40</p>
 * <p>作者：chaiys</p>
 **/
@Slf4j
public class CopyFileDemo {

    public static void main(String[] args) {
        String readFilePath = "E:\\File\\硬盘\\win10-1909.iso", writeFilePath = "E:\\File\\硬盘\\win10-1909-back.iso";
        RandomAccessFile readFile = null, writeFile = null;
        FileChannel readChannel = null, writeChannel = null;
        try {
            // 只读方式打开文件，输入流，只读即可
            readFile = new RandomAccessFile(readFilePath, "r");
            writeFile = new RandomAccessFile(writeFilePath, "rw");
            // 创建管道对象
            readChannel = readFile.getChannel();
            writeChannel = writeFile.getChannel();

            // 分块拷贝文件
            long size = readChannel.size();
            // 定义每次要拷贝的文件大小
            long transformSize = 512 * 1024 * 1024;
            // 获取需要循环的次数
            long count = size % transformSize == 0 ? size / transformSize : size / transformSize + 1;
            long startTime = System.currentTimeMillis();
            for (long i = 0; i < count; i++) {
                // 定义每次开始的位置
                long startSize = i * transformSize;
                // 定义每次要拷贝的大小
                long trueSize = Math.min(size - startSize, transformSize);
                // 创建映射缓冲数组
                MappedByteBuffer readMap = readChannel.map(FileChannel.MapMode.READ_ONLY, startSize, trueSize);
                MappedByteBuffer writeMap = writeChannel.map(FileChannel.MapMode.READ_WRITE, startSize, trueSize);
                // 循环读取数据
                for (long j = 0; j < trueSize; j++) {
                    // 读数据
                    byte b = readMap.get();
                    // 写数据
                    writeMap.put(b);
                }
            }
            long time = System.currentTimeMillis() - startTime;
            log.info("文件大小：{}MB，执行时间：{}s", size / 1024 / 1024, time / 1000);
        } catch (Exception e) {
            log.error("文件复制失败！", e);
            throw new NettyException("文件复制失败！", e);
        } finally {
            try {
                if (null != readFile) {
                    readFile.close();
                }
                if (null != writeFile) {
                    writeFile.close();
                }
                if (null != readChannel) {
                    readChannel.close();
                }
                if (null != writeChannel) {
                    writeChannel.close();
                }
            } catch (IOException ignored) {}
        }

    }
}
